package DB;

import Command.*;
import Command.SetCommand;
import Executor.DbThreadExecutor;
import com.alibaba.fastjson.JSONObject;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;


public class LogDb implements MiniDb {



    private ConcurrentHashMap<String,AbstractCommand> DbCache ;

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private Lock readLock = readWriteLock.readLock();
    private Lock WriteLock = readWriteLock.writeLock();
    /**
     * 首先淘汰淘汰队列 根据过期时间
     * 其次淘汰溢出情况 根据更新时间
     */

    //淘汰队列
    private PriorityQueue<SetCommand> EliminateQueue  = new PriorityQueue<SetCommand>(
            (a,b)-> (int) (a.getExpireTime() -b.getExpireTime())
    );


    public LogDb(String logPath){

        DbCache = new ConcurrentHashMap<String, AbstractCommand>();
        DbThreadExecutor.scheduleAtFixedRate(()->{
           cleanUpEliminateQueue();
       },2,5);


        System.out.println("Cache 初始化");

    }

    public void put(SetCommand command)  {



         new LockTemplate<String>(){

            @Override
            public String doInLockBlock() {
                try {
                   //判断有无键，若无就插入 若有就更新
                    DbCache.put(command.getKey(), command);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return  null;
            }
        }.executeSafely(WriteLock);





    }

    public void putWithExpireTime(SetCommand command){
        new LockTemplate<String>(){
            public String doInLockBlock(){
                DbCache.put(command.getKey(),command);
                AddEliminateQueue(command);
                return null;
            }
        }.executeSafely(WriteLock);

    }

    public void AddEliminateQueue(SetCommand value){
        if(EliminateQueue.contains(value)){
            EliminateQueue.remove(value);
            value.setExpireTime(System.currentTimeMillis());
        }
        EliminateQueue.add(value);

    }

    public void cleanUpEliminateQueue(){

       int removeCount =  10;
        long nowTime = System.currentTimeMillis();
        while (!EliminateQueue.isEmpty()&& removeCount-- > 10){
            System.out.println("Eliminate...");
           SetCommand value = EliminateQueue.peek();

           if( nowTime - value.getExpireTime()*1000 < value.getUpdateTime() )
           {
                break;

           }
            EliminateQueue.poll();
            DbCache.remove(value.getKey());

       }
    }

    //todo 当cache满时进行清除
    public void cleanUpOverSize(){

    }


    public String get(String key)   {
        return new LockTemplate<String>() {
            @Override
            public String doInLockBlock() {
                return getByKey(key);
            }
        }.executeSafely(readLock);

    }

    public String getByKey(String key){
        SetCommand res = (SetCommand) DbCache.get(key);
        if(res == null){
            return "null";
        }

        return res.getValue();

    }

    public void remove(String key)  {

        try {

            DbCache.remove(key);
            List<AbstractCommand> list = new ArrayList<AbstractCommand>();
            list.add(new RmCommand(key));

        }catch (Exception e){
            e.printStackTrace();
        }


    }

    /***
     *  加载aof文件
     * @param path
     */
    public void LoadAOF(String path){


        FileReader fileReader = null;
        BufferedReader bufferedReader=null;
        try {
            fileReader = new FileReader(new File(path));
            bufferedReader = new BufferedReader(fileReader);

            //遍历查找KEY 查找到返回数据
            String line = bufferedReader.readLine();//3

            LinkedList<Command> values = new LinkedList<Command>();//4
            while (line != null) {//5
                JSONObject kv = JSONObject.parseObject(line);//6
                if(kv != null){
                    //取出 k v
                    String key = kv.getString("key");
                    String value = kv.getString("value");
                    String type = kv.getString("type");
                    //判断 type  然后 往缓存放数值
                    if (CommandTypeEnum.SET.name().equals(type) ){
                            DbCache.put(key,new SetCommand(key,value));
                      }
                }
                line = bufferedReader.readLine();//8
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            try {
                bufferedReader.close();
            }catch (Exception e){
                e.printStackTrace();
            }

        }

    }


    /**
     *
      * @return
     */
    @Override
    public boolean IsFull() {
        return false;
    }

    /***
     *
     */
    @Override
    public void EliminateDb() {

    }

    /***'
     * 返回现在的容量
     * @return
     */
    public  ConcurrentHashMap<String,AbstractCommand> getNowCache(){
        return  DbCache;
    }


    /***
     * 锁模板
     * @param <T>
     */
    private  static  abstract class LockTemplate<T>{

        T executeSafely(Lock lock){
            lock.lock();
            try {
                return doInLockBlock();
            }finally {
                lock.unlock();
            }
        }

        public abstract T doInLockBlock();

    }

}
